package com.framwork.core.base;

import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.framwork.core.config.APIClientConfiguration;
import com.framwork.core.exception.EmptyValueException;
import com.framwork.core.exception.SignMsgFailedException;
import com.framwork.core.exception.SignVerifyFailedException;
import com.framwork.core.exception.SystemException;
import com.framwork.core.logging.Logger;
import com.framwork.core.logging.LoggerEvent;
import com.framwork.core.logging.LoggerFactory;
import com.framwork.core.utils.TimeCost;
import okhttp3.RequestBody;
import org.apache.commons.lang3.StringUtils;

import java.text.MessageFormat;

import static com.framwork.core.config.APIInterfaceMapping.getSplicingInput;


/**
 * @author ：james.liu
 * @date ：Created in 2021/12/14 16:37
 * @description：
 * @version: 1.0
 */
@SuppressWarnings("all")
public class DefaultAPIActionProxy implements AbstractDefaultAPIActionProxy {

    private Logger logger = LoggerFactory.getLogger(DefaultAPIActionProxy.class);

    private static final String eventName = "default-api-action-proxy";

    private static final DefaultAPIActionProxy instance = new DefaultAPIActionProxy();

    private DefaultAPIActionProxy() {
    }

    /**
     * 描述：API接口动作代理泛型方法<br/>
     *
     * @param input         入参基类
     * @param configuration 核心配置参数
     * @param httpUtils     http请求工具
     * @param clz           返回基类
     * @param requestBody   入参Body
     * @param <I>           基类
     * @param <O>           基类
     * @return
     * @throws SignMsgFailedException    签名失败
     * @throws SignVerifyFailedException 签名校验失败
     * @throws EmptyValueException       参数校验失败
     * @throws Exception                 其他异常
     */
    public <I extends AbstractAPIInput, O extends AbstractAPIResult> O doAction(
            final I input,
            final APIClientConfiguration configuration,
            final IHttpUtils httpUtils,
            final Class<O> clz,
            final RequestBody requestBody
    ) throws SignMsgFailedException, SignVerifyFailedException, EmptyValueException, Exception {
        TimeCost timeCost = new TimeCost();
        O r;
        // 校验参数
        input.checkParameter();
        String accessToken = configuration.getAccessToken();
        accessToken = (StringUtils.isEmpty(accessToken)) ? getAccessToken() : accessToken;
        if (StringUtils.isBlank(accessToken)) {
            throw new SystemException("获取accesstoken有误!");
        }
        //校验参数
        input.checkParameter();
        final String responseBody = httpUtils.postStringResult(getUrl(configuration, input.getCmdId()),
                HEADER_BEARER, accessToken, requestBody);
        logger.bind(new LoggerEvent(eventName).
                append("args", input).
                append("api", input.getCmdId()).
                append("timeCost", timeCost.cost()).
                append("result", responseBody)).info().log();
        if (StringUtils.isEmpty(responseBody)) {
            throw new EmptyValueException("responseBody is null.");
        }
        String json = responseBody;
        r = JSON.parseObject(json, clz);
        return r;

    }

    protected static final String HEADER_BEARER = "Bearer";
    protected static final String HEADER_CONTENT_TYPE = "Content-Type";

    /**
     * @param input
     * @param configuration
     * @param httpUtils
     * @param clz
     * @param requestBody
     * @param <I>
     * @param <O>
     * @return
     * @throws SignMsgFailedException
     * @throws SignVerifyFailedException
     * @throws EmptyValueException
     * @throws Exception
     */
    public <I extends AbstractAPIInput, O extends AbstractAPIResult> O doGetAction(
            final I input,
            final APIClientConfiguration configuration,
            final Class<O> clz,
            String body
    ) throws SignMsgFailedException, SignVerifyFailedException, EmptyValueException, Exception {
        TimeCost timeCost = new TimeCost();
        O r;
        // 校验参数
        input.checkParameter();
        String accessToken = configuration.getAccessToken();
        accessToken = (StringUtils.isEmpty(accessToken)) ? getAccessToken() : accessToken;
        if (StringUtils.isBlank(accessToken)) {
            throw new SystemException("获取accesstoken有误!");
        }
        final String responseBody = HttpRequest.get(getUrl(configuration, input.getCmdId())).body(body)
                .header(HEADER_BEARER, accessToken)
                .header(HEADER_CONTENT_TYPE, "application/json; charset=utf-8").execute()
                .body();
        logger.bind(new LoggerEvent(eventName).
                append("args", input).
                append("api", input.getCmdId()).
                append("timeCost", timeCost.cost()).
                append("result", responseBody)).info().log();
        if (StringUtils.isEmpty(responseBody)) {
            throw new EmptyValueException("responseBody is null.");
        }
        if (!JSONUtil.isJson(responseBody)) {
            throw new EmptyValueException(responseBody);
        }
        String json = responseBody;
        r = JSON.parseObject(json, clz);
        return r;

    }

    /**
     * 描述：API接口动作代理泛型方法<br/>
     *
     * @param input         入参基类
     * @param configuration 核心配置参数
     * @param httpUtils     http请求工具
     * @param clz           返回基类
     * @param requestBody   入参Body
     * @param <I>           基类
     * @param <O>           基类
     * @return
     * @throws SignMsgFailedException    签名失败
     * @throws SignVerifyFailedException 签名校验失败
     * @throws EmptyValueException       参数校验失败
     * @throws Exception                 其他异常
     */
    public <I extends AbstractAPIInput, O extends AbstractAPIResult> O doGetAction(
            final I input,
            final APIClientConfiguration configuration,
            final IHttpUtils httpUtils,
            final Class<O> clz,
            final String... splicing
    ) throws SignMsgFailedException, SignVerifyFailedException, EmptyValueException, Exception {
        TimeCost timeCost = new TimeCost();
        O r;
        String accessToken = configuration.getAccessToken();
        accessToken = (StringUtils.isEmpty(accessToken)) ? getAccessToken() : accessToken;
        //校验参数
        input.checkParameter();
        // 获取接口相关参数
        String send = MessageFormat.format(getSplicingInput(input.getCmdId()), splicing);
        //发起调用
        StringBuilder sb = new StringBuilder();
        final String responseBody = httpUtils.getStringResult(getUrl(configuration, input.getCmdId()));
        logger.bind(new LoggerEvent(eventName).
                append("args", input).
                append("api", input.getCmdId()).
                append("timeCost", timeCost.cost()).
                append("result", responseBody)).info().log();
        if (StringUtils.isEmpty(responseBody)) {
            throw new EmptyValueException("responseBody is null.");
        }
        String json = responseBody;
        r = JSON.parseObject(json, clz);
        return r;

    }

    /**
     * 描述：API接口动作代理泛型方法
     *
     * @param input         入参基类
     * @param configuration 核心配置参数
     * @param httpUtils     http请求工具
     * @param clz           返回基类
     * @param <I>           入参基类
     * @param <O>           出参基类
     * @return
     * @throws SignMsgFailedException    签名失败
     * @throws SignVerifyFailedException 签名校验失败
     * @throws EmptyValueException       参数校验失败
     * @throws Exception                 其他异常
     */
    public <I extends AbstractAPIInput, O extends AbstractAPIResult> O doAction(
            final I input,
            final APIClientConfiguration configuration,
            final IHttpUtils httpUtils,
            final Class<O> clz
    ) throws SignMsgFailedException, SignVerifyFailedException, EmptyValueException, Exception {
        TimeCost timeCost = new TimeCost();
        O r;
        // 校验参数
        input.checkParameter();
        String splicingInput = getSplicingInput(input.getCmdId());
        String send = MessageFormat.format(splicingInput, configuration.getAccessKey(), configuration.getAccessSecret());
        String responseBody = httpUtils.getStringResult(getUrl(configuration, input.getCmdId()));
        logger.bind(new LoggerEvent(eventName).
                append("args", input).
                append("api", input.getCmdId()).
                append("timeCost", timeCost.cost()).
                append("result", responseBody)).info().log();
        if (StringUtils.isEmpty(responseBody)) {
            throw new EmptyValueException("responseBody is null.");
        }
        String json = responseBody;
        r = JSON.parseObject(json, clz);
        return r;
    }

    public <I extends AbstractAPIInput, O extends AbstractAPIResult> O accessToken(
            final I input,
            final APIClientConfiguration configuration,
            final Class<O> clz,
            final RequestBody requestBody
    ) throws SignMsgFailedException, SignVerifyFailedException, EmptyValueException, Exception {
        TimeCost timeCost = new TimeCost();
        O r;
        // 校验参数
        input.checkParameter();
        String url = configuration.getApiUrl() + input.getCmdId();
        final String responseBody = HttpRequest.post(url)
                .header(HEADER_CONTENT_TYPE, "application/json; charset=utf-8")
                .body(input.toJsonString())
                .execute()
                .body();
//        final String responseBody = httpUtils.postStringResult(url, requestBody);
        logger.bind(new LoggerEvent(eventName).
                append("args", input).
                append("api", input.getCmdId()).
                append("timeCost", timeCost.cost()).
                append("result", responseBody)).info().log();
        if (StringUtils.isEmpty(responseBody)) {
            throw new EmptyValueException("responseBody is null.");
        }
        String json = responseBody;
        r = JSON.parseObject(json, clz);
        return r;
    }

    public <I extends AbstractAPIInput, O extends AbstractAPIResult> O accessToken(
            final I input,
            final APIClientConfiguration configuration,
            final Class<O> clz,
            final String requestBody
    ) throws SignMsgFailedException, SignVerifyFailedException, EmptyValueException, Exception {
        TimeCost timeCost = new TimeCost();
        O r;
        // 校验参数
        input.checkParameter();
        final String responseBody = HttpRequest.post(getUrl(configuration, input.getCmdId()))
                .header(HEADER_CONTENT_TYPE, "application/json; charset=utf-8")
                .body(requestBody)
                .execute()
                .body();
//        final String responseBody = httpUtils.postStringResult(url, requestBody);
        logger.bind(new LoggerEvent(eventName).
                append("args", input).
                append("api", input.getCmdId()).
                append("timeCost", timeCost.cost()).
                append("result", responseBody)).info().log();
        if (StringUtils.isEmpty(responseBody)) {
            throw new EmptyValueException("responseBody is null.");
        }
        String json = responseBody;
        r = JSON.parseObject(json, clz);
        return r;


    }


    public static DefaultAPIActionProxy getInstance() {
        return instance;
    }

}
